import json
import pickle

from django.http import HttpResponse
import random
from redis import StrictRedis

redis = StrictRedis(host='localhost', port=6379, db=0, password=None)


class task(object):
    def __init__(self, task_id, in_time, need_time):
        self.task_id = task_id
        self.in_time = in_time
        self.need_time = need_time
        self.get_time = 0
        self.finish_time = 0
        self.round_time = 0
        self.time_with = 0

    def finish(self, time):
        self.finish_time = time

    def get_ans(self):
        self.round_time = self.finish_time - self.in_time
        self.time_with = self.round_time / self.need_time


def task_init(request): # 初始化
    if request.method == 'POST':
        concat = request.POST
        try:
            task_num = int(concat["num"])
            time_slice = int(concat["time"])
        except:
            task_num = 10
            time_slice = 100
        for elem in redis.keys():  # 清空redis
            redis.delete(elem)
        ans = ''
        for i in range(task_num):
            task_in = task(i,  i * time_slice, random.randint(1, 3 * time_slice))
            ans += "任务id：" + str(i) + "     " + "到达时间：" + str(task_in.in_time) + "      " + "所需时间：" + str(
                task_in.need_time) + "\n"
            redis.rpush("task_ready", pickle.dumps(task_in))
        response = HttpResponse(json.dumps({"ans": ans}))
        response["Access-Control-Allow-Origin"] = "*"
        return response


def task_handler(request):
    if request.method == 'POST':
        concat = request.POST
        try:
            task_num = int(concat["num"])
            time_slice = int(concat["time"])
        except:
            task_num = 10
            time_slice = 100
        ans = []
        time = 0
        func = concat["func"]
        if func == 'func1':  # fun1 是先进先出
            for i in range(task_num):
                task_in = pickle.loads(redis.lpop("task_ready"))
                if task_in.in_time <= time:
                    time += task_in.need_time
                else:
                    time = task_in.in_time + task_in.need_time
                task_in.finish_time = time
                redis.rpush("finish", time)
                task_in.get_ans()
                ans.append("进程 " + str(task_in.task_id) + "    " + "完成时间 :" + str(time) + "    " + "周转时间： " + str(
                    task_in.round_time) \
                           + "    " + "带权周转时间： " + str(task_in.time_with) + "\n")
        if func == 'func2':  # fun2是最短时间优先
            for i in range(task_num):
                task_todo = pickle.loads(redis.lpop("task_ready"))
                wait_list = []  # 用来放等待的队列
                if task_todo.in_time <= time:
                    wait_list.append(task_todo)  # 下面的步骤是把当前任务完成时间之前到达的任务全部放到等待队列里，然后取出用时最短的，再放回去
                    while True:
                        try:
                            task_block = pickle.loads(redis.lpop("task_ready"))
                        except:
                            break
                        if task_block.in_time <= time:
                            wait_list.append(task_block)
                        else:
                            redis.lpush("task_ready", pickle.dumps(task_block))
                            break
                    rank_dic = {}
                    for j in range(len(wait_list)):
                        rank_dic[j] = wait_list[j].need_time
                    id_dic = sorted(rank_dic.items(), key=lambda x: x[1])
                    task_todo_index = [a[0] for a in id_dic][0]
                    task_todo = wait_list.pop(task_todo_index)
                    for t in wait_list[::-1]:
                        redis.lpush("task_ready", pickle.dumps(t))
                    time += task_todo.need_time
                else:
                    time = task_todo.in_time + task_todo.need_time
                task_todo.finish_time = time
                redis.rpush("finish", time)
                task_todo.get_ans()
                ans.append("进程 " + str(task_todo.task_id) + "    " + "完成时间 :" + str(time) + "    " + "周转时间： " + str(
                    task_todo.round_time) \
                           + "    " + "带权周转时间： " + str(task_todo.time_with) + "\n")

        if func == 'func3': # 时间片轮转算法，并不在要求范围内，具体实现方法过于复杂，写在了报告里，代码疑问可以联系 qq 418072832详细解答。
            for i in range(task_num):
                time += time_slice
                task_in = pickle.loads(redis.lpop("task_ready"))
                if redis.llen("task_in") == 0:
                    task_in.get_time += time_slice
                    if task_in.get_time > task_in.need_time:     # 一个时间片内可以完成
                        time_r = time - (task_in.get_time - task_in.need_time)
                        task_in.finish_time = time_r
                        redis.rpush("finish", time_r)
                        task_in.get_ans()
                        ans.append("进程 " + str(task_in.task_id) +"    "+ "完成时间 :" + str(time_r) +"    " + "周转时间： " + str(task_in.round_time) \
                               + "    " + "带权周转时间： " + str(task_in.time_with) + "\n")
                    else:
                        redis.rpush("task_in", pickle.dumps(task_in))
                else:
                    task0 = pickle.loads(redis.lpop("task_in"))
                    redis.rpush("wait", pickle.dumps(task_in))
                    redis.rpush("wait", pickle.dumps(task0))
                    task_todo = pickle.loads(redis.lpop("wait"))
                    task_todo.get_time += time_slice
                    if task_todo.get_time > task_todo.need_time:
                        time_r = time - (task_todo.get_time - task_todo.need_time)
                        task_todo.finish_time = time_r
                        redis.rpush("finish", time_r)
                        task_todo.get_ans()
                        ans.append("进程 " + str(task_todo.task_id) +"    " + "完成时间 :" + str(time_r) + "    "+"周转时间： " + str(task_todo.round_time) \
                               + "    " + "带权周转时间： " + str(task_todo.time_with) + "\n")
                    else:
                        redis.rpush("task_in", pickle.dumps(task_todo))

            while redis.llen("task_in") > 0:
                task_t = pickle.loads(redis.lpop("task_in"))
                if redis.llen("wait") > 0:
                    if task_t.get_time > task_t.need_time:
                        time_r = time - (task_t.get_time - task_t.need_time)
                        task_t.finish_time = time_r
                        redis.rpush("finish", time_r)
                        task_t.get_ans()
                        ans.append("进程 " + str(task_t.task_id) + "    "+ "完成时间 :" + str(time_r) + "    "+ "周转时间： " + str(task_t.round_time) \
                               +"    "+ "带权周转时间： " + str(task_t.time_with) + "\n")
                        task_w = pickle.loads(redis.lpop("wait"))
                        task_w.get_time += time_slice
                        redis.rpush("task_in", pickle.dumps(task_w))
                    else:
                        redis.rpush("wait", pickle.dumps(task_t))
                        task_w = pickle.loads(redis.lpop("wait"))
                        task_w.get_time += time_slice
                        redis.rpush("task_in", pickle.dumps(task_w))
                else:
                    time_r = time - (task_t.get_time - task_t.need_time)
                    task_t.finish_time = time_r
                    redis.rpush("finish", time_r)
                    task_t.get_ans()
                    ans.append("进程 " + str(task_t.task_id) +"    "+ "完成时间 :" + str(time_r) + "    "+"周转时间： " + str(task_t.round_time) \
                           + "    " + "带权周转时间： " + str(task_t.time_with) + "\n")
                time += time_slice
        redis.set("ans", pickle.dumps(ans))
        redis.set("end_time", time)
        response = HttpResponse(json.dumps({"stop": str(task_num)}))
        response["Access-Control-Allow-Origin"] = "*"
        return response

def task_bytime(request):  # 按时间筛选供前端显示的结果
    if request.method == 'POST':
        concat = request.POST
        time = int(concat["time"])
        try:
            num = int(concat["num"])
        except:
            num = 10
        print(time)
        ans_list = pickle.loads(redis.get("ans"))
        end_time = int(redis.get("end_time"))
        ans = ''
        percent = 0
        for i in range(time):
            ans += ans_list[i]
            a = int(redis.lindex("finish", i))
            percent = a / end_time * 100
        isfinish = False
        if time == num:
            percent = 100
            isfinish = True

        response = HttpResponse(json.dumps({"ans": ans,
                                            "percent": percent,
                                            "finish": isfinish}))
        response["Access-Control-Allow-Origin"] = "*"
        return response